Bridges > Python Bridge > Python to IDL

Python to IDL Bridge

The Python to IDL bridge provides a mechanism for calling IDL code from Python. The IDL module contains a set of methods that allow you to initialize and interact with the IDL interpreter. In addition, each object passed back from IDL is wrapped in an instance of the IDL class; you can then call methods on the underlying IDL object, or set and retrieve attributes on the object.

Note: See Python Bridge for installation instructions.

Methods and Additional Information

Examples

Call an IDL function or method directly from Python code, as if it was a Python object:

>>> from idlpy import IDL

>>> arr = IDL.findgen(100)/50*3.14159

>>> x = 50*IDL.sin(arr)

>>> y = 50*IDL.cos(arr)

>>> m = IDL.map(test=1)

% Compiled module: MAP.

>>> p = IDL.plot(x - 90, y, 'r-o2', overplot=1)

% Compiled module: PLOT.

>>> p = IDL.plot(x + 90, y, 'b-o2', overplot=1)

>>> m.save('map.png', resolution=96, border=0, transparent=1)

Notice that any output from IDL gets printed out in the Python console.

Execute the same commands, but called directly within the IDL interpreter:

>>> IDL.run("arr = findgen(100)/50*3.14159")

>>> IDL.run("help, arr", stdout=1)

ARR          FLOAT     = Array[100]

>>> IDL.run("x = 50*sin(arr)")

>>> IDL.run("y = 50*cos(arr)")

>>> IDL.run("m = map(/test)")

>>> IDL.run("p = plot(x - 90, y, 'r-o2', /overplot)")

>>> IDL.run("p = plot(x + 90, y, 'b-o2', /overplot)")

>>> IDL.run("m.save, 'map.png', resolution=96, border=0, /transparent")

Import the IDL Module

To start using the IDL module from within Python, you can use the following command:

>>> from idlpy import IDL

At this point you now have access to all of the methods on the IDL class.

IDL.run

The IDL.run method executes IDL commands within the IDL interpreter. Any output produced by IDL is either returned in the result or redirected to the Python console.

Examples

Execute some arbitrary IDL code and print the result:

>>> IDL.run('arr = FINDGEN(100)')

>>> IDL.run('help, arr', stdout=1)

ARR         FLOAT    = Array[100]

Execute multiple IDL statements using the "&" operator:

>>> result = IDL.run('for i=0,9 do begin & print, i & endfor')

>>> print(result)

0

1

...

9

Syntax

Result = IDL.run( command [, stdout=False] [, silent=False] )

Return Value

By default the return value is a Python string containing all of the IDL output. If stdout is set to True then all of IDL's output is redirected to the Python console and the return value is None.

Arguments

Command

A string containing the IDL statements to execute in the IDL interpreter. You can send a multi-statement command by using a single string and separating the statements with the IDL "&" operator.

Keywords

stdout

Set this keyword to True to redirect all of IDL's output to the Python console.

silent

Set this keyword to True to avoid saving the command to IDL's command history.

Additional Information on the IDL Class

Calling IDL Routines

Once you have imported the IDL module, you can call any function or procedure on IDL's path using the "dot" notation. Arguments and keywords can be passed to the routine. For example:

>>> from idlpy import IDL

>>> arr = IDL.randomu(None, 10000)

>>> arr = IDL.smooth(arr, 50)

>>> spec = IDL.fft_powerspectrum(arr, 0.1)

% Compiled module: FFT_POWERSPECTRUM.

>>> import matplotlib.pyplot as plt

>>> plt.semilogy(spec)

>>> plt.show()

This creates the figure shown to the right.

IDL Object Classes

If you have retrieved an object from IDL, you can call methods or get and set properties on that object by using the "dot" notation. For example, we could construct an IDL graphics plot, modify some properties on the plot, and then save the plot to a file:

>>> from idlpy import IDL

>>> import numpy.random as ran

>>> arr = ran.rand(100)

>>> p = IDL.plot(arr, title='My Plot')

>>> p.color = 'red'

>>> p.save('myplot.pdf')

>>> p.close()

Case Sensitivity

IDL variable and method names are case insensitive while Python names are case sensitive. When you call an IDL function or method, such as the save method on the IDL PLOT class, the bridge will automatically convert the name to uppercase before asking IDL for the routine.

Passing Variables to and from IDL

Normally, you will pass Python variables into IDL function calls as input arguments or keywords, and receive the result back as an Python variable. However, if you use the IDL.run method, you may want to pass variables to or from IDL directly. To do this, you can use the standard Python attribute notation on the IDL class. For example:

Set an IDL variable

>>> from idlpy import IDL

>>> import numpy.random as ran

>>> arr = ran.rand(5)

>>> IDL.arr = arr    # pass by reference

>>> IDL.run('print, arr')

0.64949746  0.42264582  0.54525948  0.54869483  0.97396999

>>> arr[0] = 99

>>> IDL.run('print, arr')

99.000000  0.42264582  0.54525948  0.54869483  0.97396999

Retrieve an IDL variable

>>> from idlpy import IDL

>>> IDL.run('arr2 = FINDGEN(10,20,30)')

>>> arr2 = IDL.arr2    # pass by value

>>> arr2.shape

(30, 20, 10)

Note: All variables that are passed from IDL back to Python will be given a lowercase name.

Retrieving IDL System Variables

To retrieve an IDL system variable such as !DPI or !CONST, you can use the Python getattr() method:

>>> from idlpy import IDL

>>> getattr(IDL, "!dpi")

3.1415926535897931

>>> const = getattr(IDL, "!const")

>>> const.keys()

dict_keys(['ME', 'PARSEC', 'DTOR', 'RYDBERG', 'MP', 'F', 'NA', 'M_EARTH', 'RE', 'P0', 'MN', 'G', 'H', 'PI', 'N0', 'T0', 'K', 'MU0', 'R_EARTH', 'VM', 'R', 'EPS0', 'LY', 'E', 'PHI', 'RTOD', 'ALPHA', 'U', 'AU', 'EULER', 'HBAR', 'I', 'GN', 'SIGMA', 'C', 'M_SUN'])

>>> const['PARSEC']

30856775814671912.0

Mechanism for Passing Parameters

Datatype Conversion

When variables are passed from IDL to Python or Python to IDL (as arguments, keywords, or __main__ variables), the following datatype conversions take place in both directions:

IDL Datatype

Python Type

!NULL (0)

None

Byte (1)

numpy.uint8

Int (2)

numpy.int16

Long (3)

numpy.int32

Float (4)

numpy.float32

Double (5)

numpy.float64, float

Complex (6)

numpy.complex64

String (7)

str, unicode

Structure (8)

see tables below

Double Complex (9)

numpy.complex128

Pointer (10)

not allowed

Objref (11)

see tables below

Uint (12)

numpy.uint16

Ulong (13)

numpy.uint32

Long64 (14)

numpy.int64

Ulong64 (15)

numpy.uint64

The following datatypes are used when converting from IDL to Python:

IDL Datatype

Python Type

Structure (8)

dict

List object

list

Hash, Dictionary, OrderedHash object

dict

IDL PYTHON object

corresponding Python object

Other IDL class

not allowed

The following datatypes are used when converting from Python to IDL:

Python Type

IDL Type

bool, numpy.bool_

Byte (1), with boolean flag

int, long

Long (3) or Long64 (14), depending upon value

float

Double (5)

complex

Double Complex (9)

bytes, bytearray

String (7)

unicode

String (7)

list

List object

tuple

List object

dict

Hash object

other Python object

IDL PYTHON object that wraps the Python object

Python IDL object

corresponding IDL PYTHON object

Array Dimensions and Array Majority

In IDL the data within a multi-dimensional array is organized as "column major," while in Python the data is organized as "row major."

Column Major Versus Row Major

In IDL, for a two-dimensional array the first dimension represents the "columns" of that array, while the second dimension represents the "rows". In terms of memory layout, the first dimension varies the "fastest", and has a stride equal to the size of the datatype in bytes. The second dimension varies the "slowest" and has a stride equal to the number of columns multiplied by the datatype size in bytes. For example, for a 16-bit integer array each column is separated by two bytes while each row is separated by 6 bytes:

IDL> x = INDGEN(3,2)+1  ; 3 columns by 2 rows

IDL> PRINT, x

1  2  3

4  5  6

IDL> PRINT, x[2,1]  ; value in column 2, row 1

6

IDL> PRINT, BYTE(x, 0, 6*2) ; print the byte representation

  1  0  2  0  3  0  4  0  5  0  6  0

In Python, for a two-dimensional array the first dimension represents the "rows" of that array, while the second dimension represents the "columns". In terms of memory layout, the first dimension varies the "slowest", and has a stride equal to the number of columns multiplied by the datatype size in bytes. The second dimension varies the "fastest" and has a stride equal to the size of the datatype in bytes. For example, for a 16-bit integer array each column is separated by two bytes while each row is separated by 6 bytes:

>>> import numpy as np

>>> x = np.array([[1, 2, 3], [4, 5, 6]], np.int16)

>>> x.shape

(2L, 3L)

>>> x.strides

(6L, 2L)

>>> x[1,2]  # value in row 1, column 2

6

>>> x.tobytes()

'\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00'

Notice that in both Python and IDL the bytes are organized the same in memory — it is only the way that the dimensions are reported and the indexing order that is different.

Array Conversion

When Python passes an array to IDL, or when IDL passes an array back to Python, the bytes within the data array remain unchanged. Instead, the order of the dimensions is reversed. For example, if we create an array in Python that has dimensions [3, 640, 480], then in IDL the dimensions will be reported as [480, 640, 3]:

>>> import numpy as np

>>> arr = np.ndarray((640, 480, 3), np.uint8)

>>> arr.shape

(640, 480, 3)

>>> IDL.arr = arr

>>> IDL.run('help, arr')

ARR BYTE = Array[3, 480, 640]

In most cases this will be the desired behavior. However, in some cases you may need to transpose your actual data values. For example, you might read in the data from a file in Python, and then run the data through an IDL or ENVI algorithm that expects a certain order. In IDL you can use the TRANSPOSE function to re-order the values within an array before sending it to Python, while in Python you can use numpy.transpose.

Version History

8.5

Introduced

See Also

!NULL, HASH, LIST, IDL to Python Bridge (PYTHON class)